#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <list>
#include <ctime>
#include <sstream>
#include <iomanip>
#include <openssl/md5.h>
#include <thread>
#include "task.h"
#include "user.h"
#include "function.h"

using namespace std;

string generateID() {
    auto now = chrono::system_clock::now();
    auto now_ms = chrono::time_point_cast<chrono::milliseconds>(now);
    auto value = now_ms.time_since_epoch().count();
    return "T" + to_string(value);
}

string encryptPassword(const string& password) {
    unsigned char digest[MD5_DIGEST_LENGTH];
    MD5((const unsigned char*)password.c_str(), password.length(), digest);
    
    stringstream ss;
    for(int i = 0; i < MD5_DIGEST_LENGTH; i++)
        ss << hex << setw(2) << setfill('0') << (int)digest[i];
    
    return ss.str();
}

void addTask(User& user, Task task) {
    if(!user.task) {
        user.task = new list<Task>();
    }
    
    for(const auto& t : *user.task) {
        if(t.start == task.start) {
            cout << "ERROR: Another task already exists at the same start time\n";
            return;
        }
    }
    
    task.id = generateID();
    task.user = user.name;
    user.task->push_back(task);
    cout << "Task added successfully!\n";
}

void saveUserTasks(const User& user) {
    string filename = user.name + ".tasks";
    ofstream file(filename);
    
    if(file.is_open()) {
        for(const auto& task : *user.task) {
            file << task.name << ","
                 << task.start << ","
                 << task.priority << ","
                 << task.group << ","
                 << task.remindTime << ","
                 << task.id << "\n";
        }
        file.close();
    }
}

void loadUserTasks(User& user) {
    string filename = user.name + ".tasks";
    ifstream file(filename);
    
    if(!user.task) {
        user.task = new list<Task>();
    } else {
        user.task->clear();
    }
    
    if(file.is_open()) {
        string line;
        while(getline(file, line)) {
            stringstream ss(line);
            Task task;
            
            getline(ss, task.name, ',');
            getline(ss, task.start, ',');
            
            string temp;
            getline(ss, temp, ',');
            task.priority = stoi(temp);
            
            getline(ss, temp, ',');
            task.group = stoi(temp);
            
            getline(ss, task.remindTime, ',');
            getline(ss, task.id, ',');
            
            task.user = user.name;
            user.task->push_back(task);
        }
        file.close();
    }
}

void del(User& user, const string& id) {
    if(!user.task) return;
    
    auto it = user.task->begin();
    while(it != user.task->end()) {
        if(it->id == id) {
            it = user.task->erase(it);
            cout << "Task deleted successfully!\n";
            return;
        } else {
            ++it;
        }
    }
    cout << "ERROR: Task not found\n";
}

void show(const User& user) {
    if(!user.task || user.task->empty()) {
        cout << "No tasks found\n";
        return;
    }
    
    auto tasks = *user.task;
    tasks.sort([](const Task& a, const Task& b) {
        return a.start < b.start;
    });
    
    cout << "ID\t\tName\tStart\t\tPriority\tGroup\tRemind Time\n";
    cout << "------------------------------------------------------------\n";
    for(const auto& task : tasks) {
        string priorityStr;
        switch(task.priority) {
            case 0: priorityStr = "Low"; break;
            case 1: priorityStr = "Medium"; break;
            case 2: priorityStr = "High"; break;
            default: priorityStr = "Unknown";
        }
        
        string groupStr;
        switch(task.group) {
            case 1: groupStr = "Study"; break;
            case 2: groupStr = "Fun"; break;
            case 3: groupStr = "Life"; break;
            default: groupStr = "Other";
        }
        
        cout << task.id << "\t"
             << task.name << "\t"
             << task.start << "\t"
             << priorityStr << "\t"
             << groupStr << "\t\t"
             << task.remindTime << endl;
    }
}

void reminderThread(const User* user) {
    while(true) {
        if(!user || !user->task) {
            this_thread::sleep_for(chrono::minutes(1));
            continue;
        }
        
        auto now = chrono::system_clock::now();
        time_t now_time = chrono::system_clock::to_time_t(now);
        tm now_tm = *localtime(&now_time);
        
        for(const auto& task : *user->task) {
            tm task_tm = {};
            istringstream ss(task.remindTime);
            ss >> get_time(&task_tm, "%Y-%m-%d %H:%M");
            
            if(ss.fail()) continue;
            
            time_t task_time = mktime(&task_tm);
            double diff = difftime(task_time, now_time);
            
            if(diff >= 0 && diff <= 60) { 
                cout << "\n!!! REMINDER !!!\n";
                cout << "Task: " << task.name << endl;
                cout << "Start Time: " << task.start << endl;
                cout << "Remind Time: " << task.remindTime << endl;
                cout << "Priority: ";
                switch(task.priority) {
                    case 0: cout << "Low"; break;
                    case 1: cout << "Medium"; break;
                    case 2: cout << "High"; break;
                }
                cout << "\nGroup: ";
                switch(task.group) {
                    case 1: cout << "Study"; break;
                    case 2: cout << "Fun"; break;
                    case 3: cout << "Life"; break;
                }
                cout << "\n\n";
            }
        }
        this_thread::sleep_for(chrono::minutes(1));
    }
}

User login(const string& name, const string& password, vector<User>& users) {
    string encrypted = encryptPassword(password);
    
    for(auto& user : users) {
        if(user.name == name && user.password == encrypted) {
            loadUserTasks(user);
            return user;
        }
    }
    
    cout << "Name or password is wrong\n";
    return {"", "", nullptr};
}

void signup(const string& name, const string& password, vector<User>& users) {
    for(const auto& user : users) {
        if(user.name == name) {
            cout << "Name already signed up\n";
            return;
        }
    }
    
    User newuser;
    newuser.name = name;
    newuser.password = encryptPassword(password);
    newuser.task = nullptr;
    users.push_back(newuser);
    
    ofstream userFile("users.dat");
    for(const auto& u : users) {
        userFile << u.name << "," << u.password << "\n";
    }
}

int trylog(vector<User>& users, User& currentUser) {
    string name, password;
    while(true) {
        cout << "Name (or 'exit' to quit): ";
        cin >> name;
        if(name == "exit") return 1;
        
        cout << "Password: ";
        cin >> password;
        
        currentUser = login(name, password, users);
        if(currentUser.name != "") {
            return 0;
        }
        
        cout << "Login failed. Try again or type 'exit' to quit\n";
    }
}
